﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using WeiTap.Validator.Internal;
using WeiTap.Validator.ValidatorSelector;

namespace WeiTap.Validator
{
    public static class ValidatorOptions
    {
        public static CasecadeMode CasecadeMode = CasecadeMode.Continue;
        public static string ProperyChainSeparator = ".";
        public static Type ResourceProviderType;

        private static ValidatorSelectorOptions validatorSelectorOptions = new ValidatorSelectorOptions();
        public static ValidatorSelectorOptions ValidatorSelectors { get { return validatorSelectorOptions; } }
        private static Func<Type, MemberInfo, LambdaExpression, string> propertyNameResolver = DefaultPropertyNameResoler;
        private static Func<Type, MemberInfo, LambdaExpression, string> displayNameResolver = DefaultDisplayNameResolver;

        public static Func<Type, MemberInfo, LambdaExpression, string> PropertyNameResolver {
            get { return propertyNameResolver; }
            set { propertyNameResolver = value ?? DefaultPropertyNameResoler; }
        }
        public static Func<Type, MemberInfo, LambdaExpression, string> DisplayNameResolver {
            get { return displayNameResolver; }
            set { displayNameResolver = value ?? DefaultDisplayNameResolver; }
        }
        static string DefaultDisplayNameResolver(Type type, MemberInfo memberInfo, LambdaExpression expression)
        {
            if (memberInfo == null) return null;
            return GetDisplayName(memberInfo);
        }

        static string DefaultPropertyNameResoler(Type type, MemberInfo memberInfo, LambdaExpression expression)
        {
            if (expression != null)
            {
                var chain = PropertyChain.FromExpression(expression);
                if (chain.Count > 0) return chain.ToString();
            }
            if (memberInfo != null)
                return memberInfo.Name;
            return null;
        }
        public static string GetDisplayName(MemberInfo member) {
            var attributes = (from attr in member.GetCustomAttributes(true)
                              select new { attr, type = attr.GetType() }).ToList();
            string name = null;
            name = (from attr in attributes where attr.type.Name == "DisplayAttribute"
                    let method = attr.type.GetRuntimeMethod("GetName", new Type[0])
                    where method != null
                    select method.Invoke(attr.attr, null) as string).FirstOrDefault();
            if (string.IsNullOrEmpty(name)) {
                name = (from attr in attributes
                        where attr.type.Name == "DisplayNameAttribute"
                        let property = attr.type.GetRuntimeProperty("DisplayName")
                        where property != null
                        select property.GetValue(attr.attr, null) as string
                      ).FirstOrDefault();
            }
            return name;
        }
    }

    public class ValidatorSelectorOptions
    {
        private Func<IValidatorSelector> defaultValidatorSelector = () =>new DefaultValidatorSelector();
        private Func<string[], IValidatorSelector> memberNameValidatorSelector = propertys => new MemberNameValidatorSelector(propertys);
        private Func<string[], IValidatorSelector> rulesetValidatorSelector = rulesets => new RulesetValidatorSelector(rulesets);
        public Func<IValidatorSelector> DefaultValidatorSelectorFactory {
            get { return defaultValidatorSelector; }
            set { defaultValidatorSelector = value ?? (() => new DefaultValidatorSelector()); }
        }
        public Func<string[], IValidatorSelector> MemberNameValidatorSelectorFactory
        {
            get { return memberNameValidatorSelector; }
            set { memberNameValidatorSelector = value ?? (properties => new MemberNameValidatorSelector(properties)); }
        }
        public Func<string[], IValidatorSelector> RulesetValidatorSelectorFactory
        {
            get { return rulesetValidatorSelector; }
            set { rulesetValidatorSelector = value ?? (rulesets=>new RulesetValidatorSelector(rulesets)); }
        }
    }
}